import React, { forwardRef, PureComponent } from 'react'
import { connect } from '@umijs/max'
import {
  Table, Spin, Empty, Pagination, Checkbox, Button, Menu, Dropdown,
} from 'antd'
import PropTypes from 'prop-types'
import _ from 'lodash'
import EmptyPic from '@/assets/images/empty.png'
import styles from './index.less'

/**
 * 1、支持Spin常用属性的透传
 * 2、bulkOperation 批量操作区，超出三个则显示下拉菜单, 回调函数参数表示选中的id
 * 3、method 设置传入请求方式
 * 4、needCode 设置是否需要返回全部请求内容
 * 5、在表格的数据源由外部传入且数据源需要分页请求时，可以直接通过 pagination参数传入 Pagination组件，由外部控制分页操作
 *
 * ProTable 组件传参分为四个部分：
 *  1)、Spin:
 *        a、spinning  是否开启自动loading功能,默认开启，值为true
 *        b、delay     延迟显示加载效果的时间（防止闪烁）
 *        c、size      组件大小，可选值为 small default large
 *        d、tip       自定义描述文案
 *        e、indicator 加载指示符
 *  2)、Table:
 *        a、columns        表格列的配置描述
 *        b、dataSource     数据源，如果传入 dataSource 数据，则配置的请求参数无效
 *        c、rowKey         表格行 key 的取值，可以是字符串或一个函数 (注意，如果传入的是一个函数，rowSelection在进行左侧下方全部勾选时不生效，还要传入个指定的rowSelectionKey值（为字符串）)
 *        d、rowSelection   表格行是否可选择,具体配置见antd table文档
 *        e、scroll         表格是否可滚动，也可以指定滚动区域的宽、高，配置见antd table文档
 *        f、sorter         排序函数，已与后端约定固定字段
 *        g、url            通过ProTable发送请求获取数据情况下，需要传入的请求地址url
 *        h、method         请求方式，默认'get'请求
 *        i、needCode       返回值是否需要统一拦截，返回全部数据
 *        j、loading        发送请求时，是否展示loading状态
 *        k、query          接口请求传入的参数
 *        l、bulkOperation  如果传入type不为'radio'的rowSelection配置项，则bulkOperation配置生效，接收一个数组，                            数组元素为对象（见示例），超过3个元素则展示更多按钮，示例：
 *                           {
                              title: 'xxx',              按钮名称
                              loading: true,             当前按钮状态
                              type:'default'             可选按钮样式
                              onClick: (params) => {},   点击事件
                             }
 *
 *        m、table其他配置项的透传
 *        n、rowSelectionKey 配合 rowKey 使用（rowKey 传入的是函数时，左下角的勾选需要传入指定的字符串key）
 *  3)、Pagination:
 *        o、queryMust 是否query必填，如果没有query，不进行请求
 *        a、showQuickJumper  是否可以快速跳转至某页
 *        b、showSizeChanger  是否展示 pageSize 切换器
 *        c、pageSize         每页条数，默认值 10，注意pageSize要单独当作一个参数来传，不要放在query里面
 *  4)、Empty:
 *        a、emptyDesc  自定义描述内容
 *        b、emptyImage 自定义空状态图片
 * */

class ProTable extends PureComponent {
  static defaultProps = {
    rowKey: 'id',
    loading: false,
    spinning: true,
    showQuickJumper: true,
    showSizeChanger: true,
    pageSize: 10,
    queryMust: false,
    jsonQueryCheck: false,
    pagination: true,
    columns: [],
  }

  static propType = {
    loading: PropTypes.bool,
    spinning: PropTypes.bool,
    delay: PropTypes.number,
    size: PropTypes.oneOf(['large', 'default', 'small']),
    tip: PropTypes.node,
    queryMust: PropTypes.bool,
    jsonQueryCheck: PropTypes.bool,
    indicator: PropTypes.node,
    columns: PropTypes.array,
    url: PropTypes.string,
  }

  state = {
    tableData: [],
    isSpin: false,
    total: 0,
    pageNum: 1,
    pageSize: this.props.pageSize,
    checked: false,
    indeterminate: false, // 全选时使用
    selectedRowKeys: [],
    selectedRows: { list: [] },
    order: null,
    orderField: null,
    query: this.props.query || {},
    // eslint-disable-next-line react/no-unused-state
    proTableQuery: {}, // 此次请求所有的参数集合(用于记录表格的检索条件)
  }

  componentDidMount() {
    const { dataSource, url } = this.props
    if (!dataSource && url) {
      this.queryTableData()
    }
  }

  /**
   * 当查询条件改变时，触发页面获取
   * @param {*} nextProps
   */
  UNSAFE_componentWillReceiveProps(nextProps) {
    if (this.props.jsonQueryCheck) {
      if (nextProps.query !== this.props.query && JSON.stringify(nextProps.query) !== JSON.stringify(this.props.query)) {
        if (this.props.queryMust && !nextProps.query) return
        this.setState(
          {
            query: nextProps.query,
          },
          () => {
            this.queryTableData()
          },
        )
      }
    } else if (nextProps.query !== this.props.query) {
        if (this.props.queryMust && !nextProps.query) return
        this.setState(
          {
            query: nextProps.query,
          },
          () => {
            this.queryTableData()
          },
        )
      }
    // 由外部传入数据源，切换页面多数据展示时，需要实时更新 pageSize 的值
    if (nextProps.pageSize !== this.props.pageSize) {
      this.setState({ pageSize: nextProps.pageSize })
    }
  }

  componentWillUnmount() {
    this.setState = (state, callback) => null
  }

  // 在table组件获取数据完成后调用
  getTableDataFinished(tableData) {
    this.props.getTableDataFinished && this.props.getTableDataFinished(tableData)
  }

  queryTableData = () => {
    const {
      url, method = 'get', needCode = false, spinning, resetExpandedRowKeys, json, queryMust,
    } = this.props
    const {
      pageNum, pageSize, order, orderField, query,
    } = this.state
    if (!url) return
    if (queryMust && (!query || Object.keys(query).length === 0)) return

    // 某些接口排序传空字符或null,或者有orderField没有order，就会报错
    if (order && order !== '') {
      query.order = order
      if (orderField && orderField !== '') query.orderField = orderField
    }

    const proTableQuery = {
      pageSize,
      pageNum,
      ...query,
    }

    this.setState({
      isSpin: !!spinning,
      // eslint-disable-next-line react/no-unused-state
      proTableQuery,
    })

    this.props.dispatch({
      type: 'global/queryTableData',
      url,
      method,
      needCode,
      json,
      params: proTableQuery,
      cb: (data) => {
        this.setState(
          {
            isSpin: false,
            pageNum: data?.pageNum || pageNum,
            pageSize: data?.pageSize || pageSize, // 外部传入的 pageSize 保存起来
            tableData: data?.list || data?.result || data || [],
            total: data?.total || data?.totalCount || data?.totalElements || 0,
            selectedRowKeys: [],
            selectedRows: { list: [] },
            checked: false,
            indeterminate: false,
          },
          () => {
            resetExpandedRowKeys && resetExpandedRowKeys() // 重新请求数据后重置上一次 额外展开的行
            this.getTableDataFinished(this.state.tableData)
            this.props.getSelectedRowKeys && this.props.getSelectedRowKeys([])
          },
        )
      },
    })
  }

  /**
   * 编辑表格的时候，更新data数据
   * */
    // eslint-disable-next-line react/no-unused-class-component-methods
  editUpdate = (updateData) => {
    this.setState({
      tableData: updateData,
    })
  }

  checkboxClick = (e) => {
    if (this.props.onCheckboxClick) {
      // table组件有个bug，data里有children字段且不等于null时，disabled字段就会消失
      // 在这里就不能真确拿到disabled属性，所以加了onCheckboxClick
      // 在组建外部通过ref去拿到data，重新对disabled赋值
      this.props.onCheckboxClick(e)
    }
    if (e.target.checked) {
      const { tableData } = this.state
      const { rowSelectionKey = '', rowKey } = this.props || {}
      const arr = []
      const objArr = []
      const key = typeof rowKey === 'function' ? rowSelectionKey : rowKey
      tableData?.map((obj) => {
        if (!obj.disabled) {
          // arr.push(obj.id)
          objArr.push(obj)
          arr.push(obj?.[key])
        }
        return null
      })
      this.setState({
        selectedRowKeys: arr,
        selectedRows: { list: [...objArr.filter(x => x)] },
      })
      this.props.getSelectedRowKeys && this.props.getSelectedRowKeys(arr)
    } else {
      this.setState({
        selectedRowKeys: [],
        selectedRows: { list: [] },
      })
      this.props.getSelectedRowKeys && this.props.getSelectedRowKeys([])
    }
    this.setState({
      checked: e.target.checked,
      indeterminate: false,
    })
  };

  /**
   * 清空表格选中的数据
   * */
    // eslint-disable-next-line react/no-unused-class-component-methods
  resetSelectedRowKeys = () => {
    this.setState({
      selectedRowKeys: [],
      selectedRows: { list: [] },
      indeterminate: false,
    })
  }

  /**
   * 重置表格页码
   * */
    // eslint-disable-next-line react/no-unused-class-component-methods
  resetPageNum = () => {
    this.setState({
      pageNum: 1,
    })
  }

  calcPagination = (defaultComp) => {
    const { pagination } = this.props
    let tempComp = null
    if (pagination) {
      if (typeof pagination === 'boolean') {
        tempComp = defaultComp
      }
      if (typeof pagination === 'object' && typeof pagination?.type === 'function') {
        tempComp = pagination
      }
    }
    return tempComp
  }

  /**
   * 删除从外部传入的 pageNum、pageSize
   * */
    // eslint-disable-next-line react/no-unused-class-component-methods
  resetPagination = () => {
    const { query } = this.state
    const tempQuery = _.cloneDeep(query)
    delete tempQuery.pageNum
    delete tempQuery.pageSize
    this.setState({
      query: tempQuery,
    })
  }

  render() {
    const {
      tableData, isSpin, total, pageNum, pageSize, selectedRowKeys, selectedRows,
    } = this.state

    const {
      columns,
      dataSource,
      rowKey,
      indicator,
      delay,
      spinSize,
      tip,
      emptyDesc,
      emptyImage,
      showQuickJumper,
      showSizeChanger,
      pagination,
      rowSelection,
      bulkOperation,
      scroll,
      showHeader,
      bordered,
      className,
      expandedRowRender,
      forceUpdateFn,
      ...other
    } = this.props
    const handleDataSource = pagination
      ? dataSource?.slice((pageNum - 1) * pageSize, pageNum * pageSize)
      : dataSource?.slice(0, dataSource.length)
    const dataSourceResTemp = dataSource ? handleDataSource : tableData
    const totalNum = Array.isArray(dataSource) ? dataSource.length : total
    // 容错处理，后端不按套路出牌
    const dataSourceRes = Array.isArray(dataSourceResTemp) ? dataSourceResTemp : []
    return (
      <Spin spinning={isSpin} delay={delay} size={spinSize} tip={tip} indicator={indicator}>
        <Table
          className={`${styles.pro_table} ${className || ''}`}
          columns={columns}
          dataSource={dataSourceRes}
          rowKey={rowKey}
          pagination={false}
          locale={{
            emptyText: (
              <Empty description={emptyDesc} image={emptyImage || EmptyPic || Empty.PRESENTED_IMAGE_SIMPLE} />
            ),
          }}
          expandable={{ expandedRowRender }}
          rowSelection={
            rowSelection
              ? {
                onSelectAll: (selected) => {
                  this.setState({
                    checked: selected,
                    indeterminate: false,
                  })
                },
                onChange: (selectedRowKeysParams, theSelectedRows) => {
                  const dataTemp = dataSource || tableData
                  let num = 0
                  dataTemp.map((obj) => {
                    if (!obj.disabled) {
                      num += 1
                    }
                    return null
                  })
                  this.setState({
                    selectedRowKeys: selectedRowKeysParams,
                    selectedRows: { list: [...theSelectedRows] },
                    indeterminate: true,
                  })
                  this.props.getSelectedRowKeys && this.props.getSelectedRowKeys(selectedRowKeysParams)
                  if (selectedRowKeysParams.length === num) {
                    this.setState({
                      checked: true,
                      indeterminate: false,
                    })
                  } else if (!selectedRowKeysParams.length) {
                    this.setState({
                      checked: false,
                      indeterminate: false,
                    })
                  } else {
                    this.setState({
                      checked: false,
                      indeterminate: true,
                    })
                  }
                },
                selectedRowKeys,
                ...rowSelection,
              }
              : undefined
          }
          // selectedRowKeys={rowSelection?.selectedRowKeys || selectedRowKeys}
          selectedRowKeys={selectedRowKeys}
          scroll={scroll}
          showHeader={!showHeader}
          onChange={(paginationParams, filters, sorter, extra) => {
            let order = null
            if (sorter.order === 'descend') {
              order = 'desc'
            } else if (sorter.order === 'ascend') {
              order = 'asc'
            }
            this.props.onChange && this.props.onChange(paginationParams, filters, sorter, extra)
            this.setState(
              {
                order,
                orderField: sorter.field,
              },
              this.queryTableData,
            )
          }}
          bordered={bordered || false}
          {...other}
        />
        {rowSelection || pagination ? (
          <div className={styles.table_footer}>
            <div className={styles.table_footer_left}>
              {rowSelection && rowSelection?.type !== 'radio' ? (
                <Checkbox
                  className={styles.checkbox_icon}
                  indeterminate={this.state.indeterminate}
                  checked={this.state.checked}
                  onClick={this.checkboxClick}
                />
              ) : null}
              {rowSelection && rowSelection?.type !== 'radio' ? (
                <div className={styles.left_tips}>
                  已选
                  <span className={styles.left_tips_num}>
                    {rowSelection?.selectedRowKeys?.length || selectedRowKeys.length}
                  </span>
                  /{dataSourceRes?.length}条
                </div>
              ) : null}
              {rowSelection && rowSelection?.type !== 'radio' && (
                <>
                  {bulkOperation?.slice(0, 3)?.map((obj, index) => (
                    <Button
                      key={obj.title}
                      className={styles.operation_btn}
                      type={obj.type || 'default'}
                      disabled={
                        // rowSelection?.selectedRowKeys?.length === 0 && selectedRowKeys.length === 0
                        selectedRowKeys?.length === 0
                      }
                      onClick={() => {
                        obj.onClick(
                          (!_.isEmpty(rowSelection?.selectedRowKeys)
                            && rowSelection?.selectedRowKeys)
                          || (!_.isEmpty(selectedRowKeys) && selectedRowKeys),
                        )
                      }}
                      loading={obj.loading}
                    >
                      {obj.title}
                    </Button>
                  ))}
                  {bulkOperation?.length > 3 && (
                    <Dropdown
                      overlayClassName={styles.dropdown_sty}
                      overlay={
                        <Menu>
                          {bulkOperation?.slice(3)?.map((obj, index) => (
                            <Menu.Item key={obj.title || index}>
                              <Button
                                key={obj.title}
                                className={styles.operation_btn}
                                disabled={
                                  rowSelection?.selectedRowKeys?.length === 0
                                  && selectedRowKeys?.length === 0
                                }
                                onClick={obj.onClick}
                                loading={obj.loading}
                              >
                                {obj.title}
                              </Button>
                            </Menu.Item>
                          ))}
                        </Menu>
                      }
                    >
                      <span className={styles.more_btn}>
                        <i className="iconfont icon-more" />
                      </span>
                    </Dropdown>
                  )}
                </>
              )}
            </div>
            <div className={styles.table_footer_right}>
              {
                this.calcPagination(
                  <Pagination
                    showQuickJumper={showQuickJumper}
                    showSizeChanger={showSizeChanger}
                    current={pageNum}
                    showTotal={() => `共${totalNum}条`}
                    total={totalNum}
                    pageSize={pageSize}
                    onChange={(pageNumParams, pageSizeParams) => {
                      this.setState({
                        pageNum: pageNumParams,
                        pageSize: pageSizeParams,
                      }, () => {
                        this.queryTableData()
                        forceUpdateFn && forceUpdateFn()
                      })
                    }}
                  />,
                )
              }
            </div>
          </div>
        ) : null}
      </Spin>
    )
  }
}

class WrappedComponentRef extends PureComponent {
  render() {
    const { forwardedRef, ...rest } = this.props
    return (
      <ProTable ref={forwardedRef} {...rest} />
    )
  }
}

const IComponent = connect(({ global }) => ({ ...global }))(WrappedComponentRef)

export default forwardRef((props, ref) => <IComponent {...props} forwardedRef={ref} />)
